#include <hal/ahci/ahci.h>
#include <hal/ahci/hba.h>
#include <string.h>

#define LOG_TAG "AHCI"
#include <log.h>

#define IDDEV_OFFMAXLBA 60
#define IDDEV_OFFMAXLBA_EXT 230
#define IDDEV_OFFLSECSIZE 117
#define IDDEV_OFFWWN 108
#define IDDEV_OFFSERIALNUM 10
#define IDDEV_OFFMODELNUM 27
#define IDDEV_OFFADDSUPPORT 69
#define IDDEV_OFFALIGN 209
#define IDDEV_OFFLPP 106
#define IDDEV_OFFCAPABILITIES 49

static uint32_t cdb_size[] = { 12, 16, 0, 0 };

void ahci_parse_dev_info(hba_dev_t* dev_info, u16* data) {
    dev_info->max_lba = *(u32*)(data + IDDEV_OFFMAXLBA);
    dev_info->block_size = *(u32*)(data + IDDEV_OFFLSECSIZE);
    dev_info->cbd_size = cdb_size[(*data & 0x3)];
    dev_info->wwn = *(u64*)(data + IDDEV_OFFWWN);
    dev_info->block_per_sec = 1 << (*(data + IDDEV_OFFLPP) & 0xF);
    dev_info->alignment_offset = *(data + IDDEV_OFFALIGN) & 0x3FFF;
    dev_info->capabilities = *((u32*)(data + IDDEV_OFFCAPABILITIES));

    if (!dev_info->block_size) {
        dev_info->block_size = 512;
    }

    if ((*(data + IDDEV_OFFADDSUPPORT) & 0x8)) {
        dev_info->max_lba = *((u64*)(data + IDDEV_OFFMAXLBA_EXT));
        dev_info->flags |= HBA_DEV_FEXTLBA;
    }

    ahci_parsestr(dev_info->serial_num, data + IDDEV_OFFSERIALNUM, 10);
    ahci_parsestr(dev_info->model, data + IDDEV_OFFMODELNUM, 20);
}

void ahci_parsestr(char* str, u16* reg_start, int size_word) {
    int j = 0;
    for (int i = 0; i < size_word; i++, j += 2) {
        uint16_t reg = *(reg_start + i);
        str[j] = (char)(reg >> 8);
        str[j + 1] = (char)(reg & 0xff);
    }
    str[j - 1] = '\0';
    strrtrim(str);
}